import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;


public class probeSender extends Thread{
	
	DatagramSocket socket;
	
	public probeSender(DatagramSocket clientSocket){
		this.socket = clientSocket;
		start();
	}
	
	public void run(){
		
		long shortTime = System.currentTimeMillis();
		long longTime = System.currentTimeMillis();
		long probeTime = System.currentTimeMillis();
		
		while(true){
			
			if(System.currentTimeMillis() - probeTime >= 25){
				for(int i:cnnode.probeCounter.keySet()){//send probe packet to everybody
					String msg = String.valueOf(System.currentTimeMillis())+ "#" + String.valueOf(cnnode.selfPort) +"#probe"; 
					byte[] sendData = msg.getBytes();
					DatagramPacket SendPacket;
					try {
						SendPacket = new DatagramPacket(sendData, sendData.length, InetAddress.getByName("localHost"), i);
						socket.send(SendPacket);
						cnnode.probeCounter.get(i).sendProbe++;
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
				
				probeTime = System.currentTimeMillis();
			}
			
		
			if(System.currentTimeMillis() - shortTime >= 1000){//display 
				displayLostRate();
				shortTime = System.currentTimeMillis();
			}
			
			if(System.currentTimeMillis() - longTime >= 5000){
				updateDV();
				cnnode.dispalayRoutingTable();
				broadcastDV();
				longTime = System.currentTimeMillis();
			}
		}
	
	}

	private void updateDV() {
		for(Integer i:cnnode.dv.keySet()){
			if(i == cnnode.selfPort){
				continue;
			}
			System.out.println("currently processing distance to: "+ i);
			double distance = 100000.00;//infinity
			int nextHop = 0;
			for(Integer j:cnnode.neighborList.keySet()){
				
				if(cnnode.neighborList.get(j)+cnnode.neighborDv.get(j).get(i) < distance){
					distance = cnnode.neighborList.get(j)+cnnode.neighborDv.get(j).get(i);
					nextHop = j;
				}
			}
			cnnode.dv.put(i, new table(nextHop, distance));
		}
		
	}

	private void broadcastDV() {
		//create dv table
		
		
		for(Integer i:cnnode.neighborList.keySet()){
			
			String table = "";
			for(Integer j:cnnode.dv.keySet()){
				if(cnnode.dv.get(j).nextHop == i  && i != j ){
					table = table + "#" + String.valueOf(j) + "#100000.00";//poison
				}
				else{
					table = table + "#" + String.valueOf(j) + "#" + String.valueOf(cnnode.dv.get(j).distance);
				}
				
			}
			table = table.substring(1);
			
			String str = table;
			if(cnnode.probeCounter.containsKey(i)){
				str = String.valueOf(System.currentTimeMillis())+ "#" + String.valueOf(cnnode.selfPort)+";"+String.valueOf(cnnode.neighborList.get(i)) +"#info#"+str; 
			}
			else{
				str = String.valueOf(System.currentTimeMillis())+ "#" + String.valueOf(cnnode.selfPort) +"#info#"+str;
			}
			byte[] sendData = str.getBytes();
			try{
				DatagramPacket SendPacket = new DatagramPacket(sendData, sendData.length, InetAddress.getByName("localHost"), i);
				socket.send(SendPacket);
			}catch (Exception e) {
				e.printStackTrace();
			}
		}
		
		
	}

	private void displayLostRate() {
		for(Integer i:cnnode.probeCounter.keySet()){
			int lostProbe = cnnode.probeCounter.get(i).sendProbe- cnnode.probeCounter.get(i).receiveProbe;
			System.out.println("Link to "+i+": "+cnnode.probeCounter.get(i).sendProbe+" packets sent, "+ lostProbe +" packets lost, loss rate "+cnnode.probeCounter.get(i).getLostRate());
			cnnode.neighborList.put(i, cnnode.probeCounter.get(i).getLostRate());//update lost rate table
		}
		
	}

}
